package com.bjpowernode.gateway.web.service.impl;

import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.bjpowernode.gateway.common.constants.KeyConst;
import com.bjpowernode.gateway.common.enums.NotifyStatus;
import com.bjpowernode.gateway.common.enums.OrderStatus;
import com.bjpowernode.gateway.common.enums.PublicStatus;
import com.bjpowernode.gateway.common.utils.HttpUtil;
import com.bjpowernode.gateway.common.utils.KqUtil;
import com.bjpowernode.gateway.common.utils.Pkipair;
import com.bjpowernode.gateway.common.utils.RedisUtil;
import com.bjpowernode.gateway.db.domain.NotifyRecord;
import com.bjpowernode.gateway.db.domain.TradeOrder;
import com.bjpowernode.gateway.db.mapper.NotifyRecordMapper;
import com.bjpowernode.gateway.db.mapper.TradeOrderMapper;
import com.bjpowernode.gateway.db.mapper.UserAccountMapper;
import com.bjpowernode.gateway.web.model.dto.KuaiQianParamDto;
import com.bjpowernode.gateway.web.model.dto.KuaiQianPaymentDto;
import com.bjpowernode.gateway.web.model.dto.KuaiQianResultDto;
import com.bjpowernode.gateway.web.model.dto.PaymentDto;
import com.bjpowernode.gateway.web.model.query.KqNoticeQeury;
import com.bjpowernode.gateway.web.model.query.NoticeBaseQeury;
import com.bjpowernode.gateway.web.model.query.TradeConfirmQuery;
import com.bjpowernode.gateway.web.service.PaymentService;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * 支付方式 多种接口实现类之一 -- 快钱
 * 处理kuaiain支付方式的所有业务代码
 * 对象名称是 方式的code
 */
@Service(value = "KUAIQIAN")
public class KuaiQianPaymentServiceImpl implements PaymentService {

    @Resource
    private RedisUtil redisUtil;

    @Resource
    private TradeOrderMapper tradeOrderMapper;

    @Resource
    private UserAccountMapper userAccountMapper;

    @Resource
    private NotifyRecordMapper notifyRecordMapper;

    @Override
    public PaymentDto createOrderGenerateApiData(TradeConfirmQuery tradeConfirmQuery) {
        KuaiQianParamDto kuaiQianParamDto = new KuaiQianParamDto();
        // 该四个值从 redis中获取
        String payConfigKey = KeyConst.USER_PAY_CONFIG + tradeConfirmQuery.getUserNo() + "#" + tradeConfirmQuery.getPayProductCode();
        String configJsonStr = redisUtil.getHashValue(payConfigKey, "CONFIG");
        String shopName = JSONUtil.parseObj(configJsonStr).getStr("shopName");
        String payConfigJsonStr = redisUtil.getHashValue(payConfigKey, "KUAIQIAN");
        String privateFile = JSONUtil.parseObj(payConfigJsonStr).getStr("privateFile");
        String merchId = JSONUtil.parseObj(payConfigJsonStr).getStr("merchId");

        // 网关流水号 :==>  时间戳 +  redis原子值
        String txNo = "KQ" + new SimpleDateFormat("yyyyMMddHHmmssSSS").format(new Date()) + redisUtil.incr(KeyConst.TX_NO_SEQ);

        kuaiQianParamDto.setMerchantAcctId(merchId);
        kuaiQianParamDto.setTerminalIp(tradeConfirmQuery.getMerchIp());
        kuaiQianParamDto.setTdpformName(shopName);
        kuaiQianParamDto.setPrivateFile(privateFile);
        kuaiQianParamDto.setTxNo(txNo);

        // 生成 支付表单中的参数值
        KuaiQianPaymentDto kuaiQianPaymentDto = new KuaiQianPaymentDto(tradeConfirmQuery, kuaiQianParamDto);
        // 插入 订单记录
        TradeOrder tradeOrder = new TradeOrder();
        tradeOrder.setId(IdWorker.get32UUID());
        tradeOrder.setUserNo(tradeConfirmQuery.getUserNo());
        tradeOrder.setUserName(shopName);
        tradeOrder.setUserOrderNo(tradeConfirmQuery.getOrderNo());
        tradeOrder.setTxNo(txNo);
        tradeOrder.setOrderAmount(tradeConfirmQuery.getOrderMoney());
        tradeOrder.setOrderTime(new Date());
        tradeOrder.setPayProductCode(tradeConfirmQuery.getPayProductCode());
        tradeOrder.setPayWayCode("HUAIQIAN");
        tradeOrder.setPayWayName("快钱");
        tradeOrder.setPayTypeCode("PC_PAY");
        tradeOrder.setPayTypeName("PC支付");
        tradeOrder.setPageurl(tradeConfirmQuery.getPageUrl());
        tradeOrder.setNotifyurl(tradeConfirmQuery.getNotifyUrl());
        tradeOrder.setRemark("添加 订单记录");
        tradeOrder.setEditTime(new Date());
        tradeOrder.setStatus(PublicStatus.ENABLE.name());
        tradeOrderMapper.insert(tradeOrder);

        return kuaiQianPaymentDto;
    }


    /**
     * 处理 异步通知
     *
     * @param noticeBaseQeury
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public KuaiQianResultDto checkHandleNotify(NoticeBaseQeury noticeBaseQeury) {
        // 向下 转型
        KqNoticeQeury receiveQuery = (KqNoticeQeury)noticeBaseQeury;
        // 判断订单是否已经被 通知  --> 查询状态
        TradeOrder tradeOrder = tradeOrderMapper.selectOne(new LambdaQueryWrapper<TradeOrder>().eq(TradeOrder::getTxNo, receiveQuery.getOrderId()));
        if (tradeOrder == null) {
            // 无效订单
            return new KuaiQianResultDto("ORDER_NONE", "http://localhost:8001/gateway/show.html");
        }
        if (!tradeOrder.getStatus().equals(OrderStatus.CREATE.name())) {
            // 不是创建 , 说明已经验证过了 , 响应时 展现给客户
            return new KuaiQianResultDto("ORDER_HANDLE", tradeOrder.getPageurl());
        }
        // 更新 订单状态   --->  10表示第三方支付成功 修改状态  | 11则为支付失败
        if ("10".equals(receiveQuery.getPayResult())) {
            // 更新订单状态
            tradeOrderMapper.update(new LambdaUpdateWrapper<TradeOrder>().set(TradeOrder::getStatus, OrderStatus.SUCCESS.name()).eq(TradeOrder::getId, tradeOrder.getId()));
            // 更新资金余额  ---> 商户 余额 和 总收入 增长
            int count = userAccountMapper.updateBalanceAndAmount(tradeOrder.getUserNo(), tradeOrder.getOrderAmount());
            if (count == 0) {
                // 更新失败
                throw new RuntimeException("更新余额失败");
            }
            // 准备异步通知  --->  将数据添加到 消息队列中  , 传输给商户
            insertNotifyRecordToMQ(tradeOrder, "ORDER_PAY_SUCC");
            return new KuaiQianResultDto("ORDER_PAY_SUCC", tradeOrder.getPageurl());
        } else {
            // 失败 , 更新状态
            tradeOrderMapper.update(new LambdaUpdateWrapper<TradeOrder>().eq(TradeOrder::getId, tradeOrder.getId()).set(TradeOrder::getStatus, OrderStatus.FAILURE.name()));
            // 准备异步通知
            insertNotifyRecordToMQ(tradeOrder, "ORDER_PAY_FAIL");
            return new KuaiQianResultDto("ORDER_PAY_FAIL", tradeOrder.getPageurl());
        }
    }

    @Override
    public String gateWayInitQuery(TradeOrder tradeOrder) {
        // 获取封装所需数据   --->  快钱方的商户id， 网关和快钱之间的orderId， 商家自己的私钥文件
        // 网关 和 快钱之间的orderid
        String orderId = tradeOrder.getTxNo();
        // 私钥文件 redis中存储的有
        // 商户id  redis中存储的有
        String key = KeyConst.USER_PAY_CONFIG + tradeOrder.getUserNo() + "#" + tradeOrder.getPayProductCode();
        String kqConfigJson = redisUtil.getHashValue(key, tradeOrder.getPayWayCode());
        JSONObject kqConfig = JSONUtil.parseObj(kqConfigJson);
        String merchId = kqConfig.getStr("merchId");
        String privateFile = kqConfig.getStr("privateFile");

        // 封装请求数据 , 到第三方支付平台去获取支付订单信息
        String respStrJson = KqUtil.kqQueryOrder(merchId , orderId , privateFile);
        // 判断 , 是否查到
        if ("error".equals(respStrJson)) {
            // 异常
            return OrderStatus.ERROR.name();
        }
        // 获取 返回回来的json中的 orderDetail
        // 解析
        JSONObject object = JSONUtil.parseObj(respStrJson);
        JSONArray orderArray = object.getJSONArray("orderDetail");
        // 判断数组是否为空
        if (JSONUtil.isNull(orderArray)) {
            return OrderStatus.NONE.name();
        } else {
            // 拿到当前条数据 ,  判断 payResult
            JSONObject orderDetail = orderArray.getJSONObject(0);
            String payResult = orderDetail.getStr("payResult");
            if ("10".equals(payResult)) {
                return OrderStatus.SUCCESS.name();
            } else {
                return OrderStatus.FAILURE.name();
            }
        }
    }
    /**
     * 添加 通知 到 redis的消息队列
     * @param tradeOrder
     * @param result
     */
    private void insertNotifyRecordToMQ(TradeOrder tradeOrder, String result) {
        // 封装对象数据 , 添加 通知记录
        NotifyRecord notifyRecord = new NotifyRecord();
        notifyRecord.setId(IdWorker.get32UUID());
        notifyRecord.setUserNo(tradeOrder.getUserNo());
        notifyRecord.setUserOrderNo(tradeOrder.getUserOrderNo());
        notifyRecord.setNotifyUrl(tradeOrder.getNotifyurl());
        notifyRecord.setNotifyTimes(0);
        notifyRecord.setMaxNotifyTimes(3);
        notifyRecord.setStatus(NotifyStatus.CREATE.name());
        notifyRecord.setEditTime(new Date());
        notifyRecord.setRemark("创建通知记录");
        notifyRecordMapper.insert(notifyRecord);

        // 将数据内容放到  redis 的消息队列当中去
        JSONObject mq = new JSONObject();
        mq.set("notifyId", notifyRecord.getId());
        mq.set("userNo", tradeOrder.getUserNo());
        mq.set("orderNo", tradeOrder.getUserOrderNo());
        mq.set("txNo", tradeOrder.getTxNo());
        mq.set("orderAmount", tradeOrder.getOrderAmount().stripTrailingZeros().toPlainString());
        mq.set("payResult", result);
        mq.set("productCode", tradeOrder.getPayProductCode());
        mq.set("payWayCode", tradeOrder.getPayWayCode());
        mq.set("notifyUrl", tradeOrder.getNotifyurl());
        redisUtil.addList(KeyConst.NOTIFY_MQ_ORIGIN , mq.toJSONString(0));
    }
}
